package se.sudoku;

import android.app.Activity;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.PowerManager;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnClickListener;
import android.view.ViewGroup.LayoutParams;
import android.widget.AbsoluteLayout;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.ProgressBar;

public class SudokuGame extends Activity {
	
	
	public ImageButton attackbtn;
	

	private Server host;
	private Client client;
	public String IP = "not set";
	private vsClient vsClient;
	private vsServer vsServer;
	
	public static final int COOP_HOST_TYPE = 0;
	public static final int COOP_CLIENT_TYPE = 1;
	public static final int VERSUS_CLIENT_TYPE = 2;
	public static final int VERSUS_HOST_TYPE = 3;
	public static final int BATTLE_CLIENT_TYPE = 4;
	public static final int BATTLE_HOST_TYPE = 5;
	public static final int SOLO_TYPE = 6;

	public int recievedAttack;
	public static int activeAttack=0;
	public static int attackPos=0;
	
	public static int numberOfTilesUsed;
	
	private digitHolder digitPopup;
	private SudokuPausMenu pausmenu;
	private SudokuWaitForOpponent waiter;
	private SudokuTimeOut timeOut;
	private static ProgressBar playerProgBar;
	private ProgressBar opponentProgBar;
	private SudokuAttacks sudokuattacks;
	private SudokuScoreBoard scoreBoard;
	
	public static int progress;
	public int type;
	public int bonusTime = 0;
    public boolean newCorrect = false;
    public int screenWidth;

	
	public final String easySudokuFacit =
		"518927436"+
		"372648159"+
		"469513287"+
		"925784361"+
		"786135942"+
		"134269875"+
		"647391528"+
		"293856714"+
		"851472693";
	
	public final String easySudoku =
		"000000000"+
		"000000000"+
		"000000000"+
		"000000000"+
		"000000000"+
		"000000000"+
		"000000000"+
		"000000000"+
		"000000000";
	
	public final String correctDigitString =
        "000000000"+
        "000000000"+
        "000000000"+
        "000000000"+
        "000000000"+
        "000000000"+
        "000000000"+
        "000000000"+
        "000000000";

	
	boolean boardChanged = false;	
	static int puzzle[];
	static int used[];
	static int facit[];
	static int correctDigit[]; 
	private static SudokuView sudoku;
	public countToAttack attackTimer;
	View v;
	
	private PowerManager.WakeLock wl;

	
	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);		
		
		//prevents screen from diming
		PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);   
		wl = pm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "DoNotDimScreen"); 
		
		
		puzzle = fromStringToPuzzle(easySudoku);
		used = puzzle.clone();
		facit = fromStringToPuzzle(easySudokuFacit);
		correctDigit = fromStringToPuzzle(correctDigitString);
		
		numberOfTilesUsed=0;
		
		IP = getIntent().getStringExtra("inputIP");
		v = getLayoutInflater().inflate(R.layout.game, null);
		type = getIntent().getIntExtra("gameType", 2);
		
		
		WindowManager w = getWindowManager(); 
        screenWidth = w.getDefaultDisplay().getWidth(); 
		
		AbsoluteLayout abl = (AbsoluteLayout) v.findViewById(R.id.attack_blockholder);
		abl.setLayoutParams(new LinearLayout.LayoutParams(screenWidth,screenWidth));
		
		sudokuattacks = new SudokuAttacks(this, screenWidth);
		digitPopup = new digitHolder(this, screenWidth);
		pausmenu = new SudokuPausMenu(this);
		waiter = new SudokuWaitForOpponent(this);
		timeOut = new SudokuTimeOut(this);
		scoreBoard = new SudokuScoreBoard(this);
		
		//progressbars
		playerProgBar = (ProgressBar)v.findViewById(R.id.game_playerProgBar);
		opponentProgBar = (ProgressBar)v.findViewById(R.id.game_opponentProgBar);
			
		switch(type){
			case(COOP_HOST_TYPE):
				loadPuzzle();
				host = new Server(this);
				new Thread(host).start();
				break;
			case(COOP_CLIENT_TYPE):
				IP = getIntent().getStringExtra("inputIP");
				client = new Client(this);
				new Thread(client).start();
				break;
			case(VERSUS_HOST_TYPE):
				loadPuzzle();
				vsServer = new vsServer(this);
				new Thread(vsServer).start();
				break;
			case(VERSUS_CLIENT_TYPE):
				IP = getIntent().getStringExtra("inputIP");
				vsClient = new vsClient(this);
				new Thread(vsClient).start();
				break;
			case(BATTLE_HOST_TYPE):
				loadPuzzle();
				vsServer = new vsServer(this);
				new Thread(vsServer).start();
				setBattleMode();
				break;
			case(BATTLE_CLIENT_TYPE):
				IP = getIntent().getStringExtra("inputIP");
				vsClient = new vsClient(this);
				new Thread(vsClient).start();
				setBattleMode();
				break;
			case(SOLO_TYPE):
				loadPuzzle();
				opponentProgBar.setVisibility(View.GONE);
				break;
		}
		
		//initialize the number of already used tiles (used[])
		initNumberOfTilesUsed();
		

		sudoku = (SudokuView)v.findViewById(R.id.sudokuview);
		setContentView(v);
		//v.requestFocus();
		
		calcProgress();
		setPlayerProgBarValue();
	}

    @Override
    public void onDestroy()
    {
    	super.onDestroy();
    	if(type==COOP_HOST_TYPE)
    	{
    		host.hasQuit=true;
    		Log.d("FORCEQUIT","SERVER QUIT");
    	}
    	if(type==COOP_CLIENT_TYPE)
    	{
    		client.hasQuit=true;
			Log.d("FORCEQUIT","CLIENT QUIT");
    	}
    	if(type==VERSUS_CLIENT_TYPE || type==BATTLE_CLIENT_TYPE)
    	{
    		vsClient.hasQuit=true;
    		Log.d("FORCEQUIT","CLIENT QUIT");
    		//vsClient.clientSocket.close();
    		if(type==BATTLE_CLIENT_TYPE){attackTimer.cancel();}
    		
    	}
    	if(type==VERSUS_HOST_TYPE || type==BATTLE_HOST_TYPE)
    	{
    		vsServer.hasQuit=true;
    		//vsServer.hostSocket.close();
    		Log.d("FORCEQUIT","HOST QUIT");
    		if(type==BATTLE_HOST_TYPE){attackTimer.cancel();}
    	}    	
    }
    
    
    @Override  
    protected void onPause() {   
        super.onPause();   
        wl.release();   
    }   
  
    @Override  
    protected void onResume() {   
        super.onResume();   
        wl.acquire();   
    } 
    
    public void loadPuzzle(){
    	
    	puzzle = getIntent().getIntArrayExtra("puzzle");
		used = puzzle.clone();
		facit = getIntent().getIntArrayExtra("facit");   	
    }
    
    public void setBattleMode(){
		//attackbtn
		attackbtn = (ImageButton) v.findViewById(R.id.attackbtn);
		attackbtn.setOnClickListener(gameButtonListener);
		attackbtn.setVisibility(View.VISIBLE);
		//start attack timer (1,5 min)
		attackTimer = new countToAttack(90000, 10000);
		attackTimer.start();
	}

    private void initNumberOfTilesUsed()
    {
	    //count number of used tiles
		for (int i =0; i<81; i++)
	    {
	    	if(used[i] != 0)
	    	{	
	    		numberOfTilesUsed++;
	    	}
	    }
    }
    

	static protected void setValues(int val){
		sudoku.setSelectedTile(val);
		
	}
		
	public void toggleDigits()
	{
		digitPopup.toggleDigitHolder();
	}
	
	public void togglePausMenu(){
		pausmenu.togglePausWindow();
	}
	
	public void toggleWaitForOpponent(){
		
		int type = getGameType();
		Log.v("toggle","after int type = getGameType()");
		String ip = "no ip";
		if (type == COOP_HOST_TYPE)
		{
			ip = host.getIp();
		}
		else if(type == VERSUS_HOST_TYPE)
		{
			ip = vsServer.getIp();
		}
		else if(type == BATTLE_HOST_TYPE)
		{
			ip = vsServer.getIp();
		}
		
		
		waiter.toggleWaitForOpponentWindow(ip);
		//timeOut.toggleTimeOutWindow();
		
		
	}
	
	public void closeWaitForOpponent(){
		waiter.closeWaitForOpponentWindow();		
	}

	public void toggleTimeOut(){
		timeOut.toggleTimeOutWindow();		
	}
	
	
	
	//Check if tile is already filled
 	protected boolean isTileValid(int x,int y)
    {    	
    	if(used[y*9 + x]!=0)
    	{
    		return false;
    	}
    	
    	return true;
    }
    //Return the tile at the given coordinates
    private int getTile(int x, int y) {
    	return puzzle[y * 9 + x];
    }
    
    protected boolean isCorrectBoard()
    {
    	for(int i=0;i<9;i++)
    	{
    		for(int j=0;j<9;j++)
    		{
    			
    			if(puzzle[i*9+j] != facit[i*9+j]) 
    			{
    				return false;
    			}
    			    		
    		}
    		
    	}
    	return true;
    }
    //Change the tile at the given coordinates
    protected void setTile(int x, int y, int value) {
        
    	setBoardChanged(true);

    	    	
    	Log.v("value","" + value);
    	//Check if tile is used or not and increment/decrement counter
    	if(puzzle[y * 9 + x]==0)
    	{
    		if(value!=0)
    		{
    			Log.d("text","success");
    			numberOfTilesUsed++;
    		}
    	}
    	else
    	{
    		if(value==0)
    		{
    			numberOfTilesUsed--;
    			
    		}
    	}
    	
    	//add value to puzzle
    	puzzle[y * 9 + x] = value;
    	       
        
        if(value==facit[y * 9 + x]) {

        	if(correctDigit[y * 9 + x] == 0)
        	{
            	//Decrease timer by 15 seconds        		
	        	newCorrect = true;
        		//Insert coordinate into "correctDigit" 
	        	correctDigit[y * 9 + x] = 1;
	        	Log.v("new correct","timer");
        	}
        }

    	//If all tiles are used check if board is finished (just for single player)
    	if(type == SOLO_TYPE && numberOfTilesUsed == 81)
    	{
    	   	if(isCorrectBoard())
    	   	{
	    		Log.d("board","correct board");
	    		setScoreBoard(0);
    	   	}
    	}
    	
    	
    }
    public int getNumUsedTiles()
    {
    	return numberOfTilesUsed;
    }
    public void setScoreBoard(int i)
    {
    	scoreBoard.toggleScoreBoardWindow(i);
    	
    }
    
    //Convert an array into a puzzle string
    static private String toPuzzleString(int[] puz) {
	    StringBuilder buf = new StringBuilder();
	    for (int element : puz) {
	    	buf.append(element);
	    }
	    return buf.toString();
    }
    
    //Convert a puzzle string into an array
    static protected int[] fromStringToPuzzle(String string) {
	    int[] puz = new int[string.length()];
	    for (int i = 0; i < puz.length; i++) {
	    	puz[i] = string.charAt(i) - '0' ;
	    }
	    return puz;
    }
    // Return a string for the tile at the given coordinates
    protected String getTileString(int x, int y) {
	    int v = getTile(x, y);
	    if (v == 0)
	    	return "" ;
	    else
	    	return String.valueOf(v);

    }
    
    public String getBoard(){
    	return toPuzzleString(puzzle);   	
    }
    
    public String getFacit(){
    	return toPuzzleString(facit);   	
    }
    
    public void setBoard(String s){
    	puzzle = fromStringToPuzzle(s);
    }

    public void setStartingBoard(String s){
    	puzzle = fromStringToPuzzle(s);
    	used = puzzle.clone();
    	numberOfTilesUsed=0;
    	initNumberOfTilesUsed();
    }    
    
    public void setFacit(String s){
    	facit = fromStringToPuzzle(s);
    }
   
    //progressbars
    public static void setPlayerProgBarValue(){
    	playerProgBar.setProgress(progress);
    }    
    
    public void setOpponentProgBarValue(int val){
    	opponentProgBar.setProgress(val);
    }
    
    public static void calcProgress(){
    	progress = 0;
    	
    	for (int i = 0 ; i < puzzle.length ; i++ ){
    		if(puzzle[i]!=0){progress++;}
    	}
    }
    
    public int getProgress(){    	
    	return progress;
    }
    public int getGameType()
    {
    	return type;
    }
    
	//attacks
    public void startAttackedMode(int val){
		sudokuattacks.startAttackMode(val);
	}
	public void getAttacked(int val, int pos){
		sudokuattacks.getAttacked(val, pos);
	}
	protected static void setAttack(int val, int pos){
		activeAttack=val;	
		attackPos=pos;
	}
	public void setBoardChanged(boolean changed){
		boardChanged=changed;
	}
	public boolean getBoardChanged(){
		return boardChanged;		
	}

    public void redrawBoard()
    {
    	sudoku.invalidate();
    }
    
    
    //GAME BUTTON LISTERNERS
    private OnClickListener gameButtonListener = new OnClickListener() {            
        public void onClick(View v){
            sudokuattacks.Attack(recievedAttack);
            
            attackTimer = new countToAttack(90000, 1000);
            attackTimer.start();
            Log.v("new timer","timer");
            
            attackbtn.setImageBitmap(null);
            attackbtn.setEnabled(false);
        }
    };
   
    //sets attackbtn to correct attack
    public void setAttackBtn(int attackNbr){
            switch(attackNbr){
            //increment
            case 1:
                    attackbtn.setImageResource(R.drawable.incrementdigits);
                    break;
            //crazy
            case 2:
                    attackbtn.setImageResource(R.drawable.crazymode);
                    break;
            //removeDigit
            case 3:
                    attackbtn.setImageResource(R.drawable.removedigit);
                    break;
            //hideBlock
            case 4:
                    attackbtn.setImageResource(R.drawable.hideblockicon);
                    break;                  
            }
            recievedAttack = attackNbr;
            attackbtn.setEnabled(true);
    }
           
    //timer that counts down to attack
    public class countToAttack extends CountDownTimer{

            public countToAttack(long millisInFuture, long countDownInterval) {
                    super(millisInFuture, countDownInterval);
                    newCorrect = false;
                    bonusTime = 0;
            }

            @Override
            public void onFinish() {
                    //set attackbtn to new attack
                    setAttackBtn(sudokuattacks.getRandomAttack());
                    Log.v("attack received","timer");
                    bonusTime = 0;
                    newCorrect = false;
                    
            }

            @Override
            public void onTick(long millisUntilFinished) {
            	if(newCorrect) {
            		bonusTime += 15;
            		Log.v("bonusTime + 15","timer");
            		if(millisUntilFinished - bonusTime*1000 <= 0){
            			newCorrect = false;
            			onFinish();
            		}
            		
            	}
            }
    }  

}

